package cn.billho.popcache.starter.aop;

import cn.billho.popcache.annotation.Cache;
import cn.billho.popcache.core.api.ICacheApi;
import cn.billho.popcache.core.codec.IResultParse;
import cn.billho.popcache.core.codec.ISerialize;
import cn.billho.popcache.core.key.IKeyGenerate;
import cn.billho.popcache.core.model.CacheBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.sql.Timestamp;

@Aspect
@Service
@Slf4j
public class PopCacheAspect {

    @Autowired
    ICacheApi cacheApi;

    @Autowired
    IKeyGenerate keyGenerate;

    @Autowired
    IResultParse resultParse;

    @Autowired
    ISerialize serialize;

    @Autowired
    ApplicationContext context;

    String app="";

    @Autowired
    public void init(){
        Environment environment = context.getBean(Environment.class);
        app= environment.getProperty("spring.application.name");
//        Preconditions.checkArgument(StringUtils.isNotBlank(app),"请配置应用名：spring.application.name");
    }

    @Pointcut("@annotation(cn.billho.popcache.annotation.Cache)")
    public void aspect() {
    }

    @Around("aspect()&&@annotation(anno)")
    public Object interceptor(ProceedingJoinPoint invocation, Cache anno)
            throws Throwable {
        MethodSignature signature = (MethodSignature) invocation.getSignature();
        Method method = signature.getMethod();
        Object result = null;
        Class<?>[] parameterTypes = method.getParameterTypes();
        Object[] arguments = invocation.getArgs();
        String region = "";
        String key = "";

        String value = "";

        try {
            region = StringUtils.isBlank(anno.region())? null : keyGenerate.buildKey(anno.region(), parameterTypes, arguments);
            key = keyGenerate.buildKey(anno.key(), parameterTypes, arguments);
            // region 和key都为空
            if(StringUtils.isBlank(key)){
                log.error("缓存key为空,缓存失效=>" + method.getName());
                return invocation.proceed();
            }

            if (StringUtils.isNotBlank(region)){
                // 有region
                CacheBean cacheBean = cacheApi.get(region, key);
                if (null != cacheBean && cacheBean.getExpireAt().getTime() > System.currentTimeMillis()){
                    //有缓存
                    Type returnType = method.getGenericReturnType();
                    result = resultParse.parse(cacheBean.getValue(),returnType,null);
                    return result;
                }
                else{
                    // 无缓存
                    result = invocation.proceed();
                    if(null == result){
                        return result;
                    }
                    Timestamp expireAt = new Timestamp(((long)anno.expireSeconds()) * 1000 + System.currentTimeMillis());
                    String beanKey = region + ":" + key;

                    cacheBean = CacheBean.builder()
                            .key(beanKey)
                            .value(serialize.serialize(result))
                            .expireAt(expireAt)
                            .appName(app)
                            .build();
                    cacheApi.set(region, key, cacheBean);
                    return result;
                }
            }
            else{
                //region is blank
                CacheBean cacheBean = cacheApi.get( key);
                if (null != cacheBean && cacheBean.getExpireAt().getTime() > System.currentTimeMillis()){
                    //有缓存
                    Type returnType = method.getGenericReturnType();
                    result = resultParse.parse(cacheBean.getValue(),returnType,null);
                    return result;
                }
                else{
                    // 无缓存
                    result = invocation.proceed();
                    if(null == result){
                        return result;
                    }
                    Timestamp expireAt = new Timestamp(((long)anno.expireSeconds()) * 1000 + System.currentTimeMillis());
                    String beanKey = key;
                    cacheBean = CacheBean.builder()
                            .key(beanKey)
                            .value(serialize.serialize(result))
                            .expireAt(expireAt)
                            .appName(app)
                            .build();
                    cacheApi.set( key, cacheBean);
                    return result;
                }
            }
        } catch (Exception e) {
            log.error("获取缓存失败：" +"region=>" + region+ ",key=>" + key + ", value=>" + value, e);
        }
        return result;
    }
}
